﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Smarly.Idml.Package.Resources
{
	public class Fonts : PackageFile
	{
		#region constants

		#endregion

		#region XDocument elements

		private static readonly XNamespace IdPkgNamespace = "http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging";
		private readonly XDocument _doc;

		#endregion

		public Fonts()
		{
			_doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement(IdPkgNamespace + "Fonts",
																																								 new XAttribute(XNamespace.Xmlns + "idPkg", IdPkgNamespace),
																																								 new XAttribute(XName.Get("DOMVersion"), "8.0")
																																			));

			List<FontBase> fonts = new List<FontBase>
				                       {
					                       new FontBase
						                       {
							                       Family = "SchoolBookC",
																		 FontStyle = FontBase.FontStyleType.Regular,
						                       },
					                       new FontBase
						                       {
							                       Family = "SchoolBookC",
																		 FontStyle = FontBase.FontStyleType.Bold,
						                       },
					                       new FontBase
						                       {
							                       Family = "SchoolBookC",
																		 FontStyle = FontBase.FontStyleType.Italic,
						                       },
					                       new FontBase
						                       {
							                       Family = "SchoolBookC",
																		 FontStyle = FontBase.FontStyleType.BoldItalic,
						                       },
					                       new FontBase
						                       {
							                       Family = "CourierC",
																		 FontStyle = FontBase.FontStyleType.Regular,
						                       },
					                       new FontBase
						                       {
							                       Family = "CourierC",
																		 FontStyle = FontBase.FontStyleType.Bold,
						                       },
					                       new FontBase
						                       {
							                       Family = "Helios",
																		 FontStyle = FontBase.FontStyleType.Regular,
						                       },
					                       new FontBase
						                       {
							                       Family = "Helios",
																		 FontStyle = FontBase.FontStyleType.Bold,
						                       },
				                       };

			foreach (var font in fonts)
			{
				AddFont(font);
			}
		}

		public override XDocument Document
		{
			get { return _doc; }
		}

		public string GenerateFontFamilyId
		{
			get
			{
				const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
				var random = new Random();
				string result;
				do
				{
					result = "di" + new string(
														Enumerable.Repeat(chars, 3)
																			.Select(s => s[random.Next(s.Length)])
																			.ToArray());
				} while (GetFamilyById(result).SingleOrDefault() != null);

				return result;
			}
		}

		internal void AddFont(FontBase fontBase)
		{
			var family = GetFamilyByName(fontBase.Family).SingleOrDefault() ?? AddFamilyFont(GenerateFontFamilyId, fontBase.Family);

			family.Add(fontBase.Element(family.Attribute("Self").Value));
		}

		private XElement AddFamilyFont(string self, string familyName)
		{
			XElement result = new XElement(
					XName.Get("FontFamily"),
					new XAttribute(XName.Get("Self"), self),
					new XAttribute(XName.Get("Name"), familyName)
				);
			Document.Root.Add(result);
			return result;
		}

		private IEnumerable<XElement> GetFamilyByName(string fontFamilyName)
		{
			return Document.Root.Descendants("FontFamily").Where(x => x.Attribute("Name") != null && x.Attribute("Name").Value == fontFamilyName);
		}

		private IEnumerable<XElement> GetFamilyById(string id)
		{
			return Document.Root.Descendants("FontFamily").Where(x => x.Attribute("Self") != null && x.Attribute("Self").Value == id);
		}

		public void RemoveFontFamily(string fontFamilyName)
		{
			foreach (var fontFamliy in GetFamilyByName(fontFamilyName).ToList())
			{
				fontFamliy.Remove();
			}
		}

		public override string Folder
		{
			get { return "Resources"; }
		}

		public override string FileName
		{
			get { return "Fonts.xml"; }
		}


		#region Font

		internal class FontBase
		{
			internal enum FontStyleType
			{
				Regular,
				Bold,
				Italic,
				BoldItalic
			}

			internal virtual string Family { get; set; }

			internal virtual FontStyleType FontStyle { get; set; }

			internal XElement Element(string familySelf)
			{
				XElement el = new XElement("Font");

				string fontStyleName = FontStyle.ToFontStyleName();
				string postScriptName = FontStyle.ToPostScriptName();
				el.Add(new XAttribute("Self", string.Format("{0}Fontn{1} {2}", familySelf, Family, fontStyleName)));
				el.Add(new XAttribute("Name", string.Format("{0} {1}", Family, fontStyleName)));
				el.Add(new XAttribute("PostScriptName", string.Format("{0}{1}{2}", Family, (string.IsNullOrWhiteSpace(postScriptName) ? string.Empty : "-"), postScriptName)));
				el.Add(new XAttribute("FontStyleName", fontStyleName));
				el.Add(new XAttribute("FullName", string.Format("{0}{1}", Family, (string.IsNullOrWhiteSpace(postScriptName) ? string.Empty : " " + fontStyleName))));
				el.Add(new XAttribute("FullNameNative", string.Format("{0} {1}", Family, fontStyleName)));
				el.Add(new XAttribute("FontStyleNameNative", fontStyleName));

				el.Add(new XAttribute("FontFamily", Family));
				el.Add(new XAttribute("PlatformName", "$ID/"));
				el.Add(new XAttribute("WritingScript", "7"));
				el.Add(new XAttribute("FontType", "OpenTypeCFF"));

				return el;
			}

		}


		#endregion


	}

	internal static class StyleExt
	{
		internal static string ToFontStyleName(this Fonts.FontBase.FontStyleType fontStyle)
		{
			switch (fontStyle)
			{
				case Fonts.FontBase.FontStyleType.Regular:
					return "Regular";
				case Fonts.FontBase.FontStyleType.Bold:
					return "Bold";
				case Fonts.FontBase.FontStyleType.Italic:
					return "Italic";
				case Fonts.FontBase.FontStyleType.BoldItalic:
					return "Bold Italic";
				default:
					throw new ArgumentOutOfRangeException("fontStyle: " + Enum.GetName(typeof(Fonts.FontBase.FontStyleType), fontStyle));
			}
		}

		internal static string ToPostScriptName(this Fonts.FontBase.FontStyleType fontStyle)
		{
			switch (fontStyle)
			{
				case Fonts.FontBase.FontStyleType.Regular:
					return "";
				case Fonts.FontBase.FontStyleType.Bold:
					return "Bold";
				case Fonts.FontBase.FontStyleType.Italic:
					return "Italic";
				case Fonts.FontBase.FontStyleType.BoldItalic:
					return "BoldItalic";
				default:
					throw new ArgumentOutOfRangeException("fontStyle: " + Enum.GetName(typeof(Fonts.FontBase.FontStyleType), fontStyle));
			}
		}
	}

}